﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Internal.Runtime.Services.Battle.Behaviour;
using KuiHuaBaoDian.Services.Lockstep;
using Runtime.Services.Battle.Entity;
using Runtime.Services.Battle.StateMachine;
using UnityEngine;
using UnityEngine.Pool;

namespace Runtime.Services.Battle.Behaviour {

    /// <summary>
    /// 战斗行为
    /// </summary>
    public interface IDFR_BattleBehaviour : IDFR_Object {

        public interface IEntity : IDFR_BattleEntityBase {
        }

        /// <summary>
        /// 逻辑触发
        /// </summary>
        /// <param name="frameIndex">帧号</param>
        /// <param name="parameter">参数</param>
        IDFR_BattleBehaviourInfo LogicFrame(int frameIndex, object parameter = null);

        /// <summary>
        /// 帧触发
        /// </summary>
        /// <param name="info"></param>
        void Execute(IDFR_BattleBehaviourInfo info);

        /// <summary>
        /// 渲染
        /// </summary>
        void Update();

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="gameObject">GameObject对象</param>
        /// <param name="stateMachine">状态机</param>
        void Initialize(IEntity entity, GameObject gameObject, IDFR_BattleEntityStateMachine stateMachine);
    }

    public abstract class DFR_BattleBehaviour : DFR_BattleBehaviour<IDFR_BattleBehaviourInfo> {
    }

    public abstract class DFR_BattleBehaviour<TInfo> : DFR_BattleBehaviour<TInfo, object> where TInfo : IDFR_BattleBehaviourInfo {

        protected abstract TInfo LogicFrame();

        [Obsolete]
#pragma warning disable CS0809 // 过时成员重写未过时成员
        protected sealed override TInfo LogicFrame(object parameter) => LogicFrame();
#pragma warning restore CS0809 // 过时成员重写未过时成员
    }

    public abstract class DFR_BattleBehaviour<TInfo, TParameter> : DFR_PoolObject, IDFR_BattleBehaviour where TInfo : IDFR_BattleBehaviourInfo where TParameter : class {

        private record UpdateInfo(float StartFrameTime, float TotalTime);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected static F64 Delta(F64 @in) => @in * LockstepService.Instance.FrameLength;

        private static readonly ObjectPool<Queue<IDFR_BattleBehaviourInfo>> m_QueuePool = new(() => new(), actionOnRelease: item => item.Clear(), collectionCheck: false);

        protected GameObject GameObject { get; private set; }

        protected Transform Transform { get; private set; }

        protected IDFR_BattleEntityStateMachine StateMachine { get; private set; }

        private IDFR_BattleBehaviour.IEntity m_Entity;
        protected IDFR_BattleBehaviour.IEntity Entity => m_Entity;

        private Queue<IDFR_BattleBehaviourInfo> m_BehaviourInfoQueue;

        protected TInfo CurrentBehaviourInfo => (TInfo)m_BehaviourInfoQueue.Peek();

        protected override void Allocate() {
            m_BehaviourInfoQueue = m_QueuePool.Get();
        }

        protected override void Release() {
            GameObject = null;
            Transform = null;
            StateMachine = null;
            m_Entity = null;

            if (m_BehaviourInfoQueue != null) {
                m_QueuePool.Release(m_BehaviourInfoQueue);
                m_BehaviourInfoQueue = null;
            }
        }

        protected abstract void Initialize();
        public void Initialize(IDFR_BattleBehaviour.IEntity entity, GameObject gameObject, IDFR_BattleEntityStateMachine stateMachine) {
            GameObject = gameObject;
            Transform = gameObject.transform;
            StateMachine = stateMachine;
            m_Entity = entity;
            Initialize();
        }

        protected abstract TInfo LogicFrame(TParameter parameter);
        IDFR_BattleBehaviourInfo IDFR_BattleBehaviour.LogicFrame(int frameIndex, object parameter) {
            if (IsDisposed) {
                return null;
            }
            var behaviourInfo = LogicFrame(parameter == null ? null : (TParameter)parameter);
            if (behaviourInfo is IDFR_BattleBehaviourInfoInternal @internal) {
                @internal.FrameIndex = frameIndex;
            }
            return behaviourInfo;
        }

        protected abstract void Execute(TInfo info);
        void IDFR_BattleBehaviour.Execute(IDFR_BattleBehaviourInfo info) {
            if (IsDisposed) {
                return;
            }
            if (info == null) {
                return;
            }
            Execute((TInfo)info);
            m_BehaviourInfoQueue.Enqueue(info);
        }

        protected abstract void Update(TInfo info, float interpolation);
        void IDFR_BattleBehaviour.Update() {
            if (IsDisposed) {
                return;
            }
            while (m_BehaviourInfoQueue.Count > 0) {
                var behaviourInfo = m_BehaviourInfoQueue.Peek();
                var frameIndex = (behaviourInfo as IDFR_BattleBehaviourInfoInternal).FrameIndex;
                var elapsedTime = LockstepService.Instance.AccumulatedTime - frameIndex * LockstepService.Instance.FrameLengthRaw;
                var interpolation = elapsedTime / LockstepService.Instance.FrameLengthRaw;
                //UnityEngine.Debug.Log($"{nameof(interpolation)}:{interpolation},{LockstepService.Instance.AccumulatedTime},{nameof(frameIndex)}:{frameIndex}");
                if (interpolation >= 0f) {
                    Update((TInfo)behaviourInfo, Mathf.Min(interpolation, 1f));
                }
                if (interpolation >= 1f) {
                    m_BehaviourInfoQueue.Dequeue();
                    if (behaviourInfo is IDisposable disposable) {
                        disposable.Dispose();
                    }
                    continue;
                }
                break;
            }
        }
    }
}
